package com.stone.stoneanswer.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.stone.stoneanswer.common.ErrorCode;
import com.stone.stoneanswer.exception.BusinessException;
import com.stone.stoneanswer.exception.ThrowUtils;
import com.stone.stoneanswer.manager.AiManager;
import com.stone.stoneanswer.model.dto.ai.ResultAnalyzeRequest;
import com.stone.stoneanswer.model.dto.answer.AnswerResultAddRequest;
import com.stone.stoneanswer.model.dto.answer.AnswerResultGetRequest;
import com.stone.stoneanswer.model.entity.AnswerResult;
import com.stone.stoneanswer.model.entity.Question;
import com.stone.stoneanswer.model.entity.QuestionOption;
import com.stone.stoneanswer.model.entity.User;
import com.stone.stoneanswer.model.vo.AnswerResultVO;
import com.stone.stoneanswer.service.AnswerResultService;
import com.stone.stoneanswer.mapper.AnswerResultMapper;
import com.stone.stoneanswer.service.QuestionBankService;
import com.stone.stoneanswer.service.QuestionService;
import com.stone.stoneanswer.service.UserService;
import com.zhipu.oapi.service.v4.model.ModelData;
import io.reactivex.Flowable;
import io.reactivex.Scheduler;
import io.reactivex.schedulers.Schedulers;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;

/**
 * @author 35431
 * @description 针对表【answer_result(题目作答结果表)】的数据库操作Service实现
 * @createDate 2025-03-20 11:44:00
 */
@Service
public class AnswerResultServiceImpl extends ServiceImpl<AnswerResultMapper, AnswerResult>
        implements AnswerResultService {

    @Resource
    private UserService userService;

    @Resource
    private QuestionService questionService;

    @Resource
    private AiManager aiManager;

    private static final String AI_RESULT_ANALYZE_SYSTEM_MESSAGE = "你是一位精通各门学科的学习指导专家，你需要根据学生所做题库的答题情况分析该学生在哪些方面有不足，并给出知识评价和建议，我会给你如下信息：\n" +
            "\n" +
            "```\n" +
            "题库名称，\n" +
            "学生答题题目和答题结果信息，格式为[{\"title\":\"题干信息\",\"options\":\"[{'key':'选项的Key','value':'选项的内容'},{其它选项}]\",\"questionAnswer\":\"题目正确答案\",\"userAnswer\":\"学生答案\"}]，如果该题为判断题，则题目答案和学生答案中0代表错误，1代表正确\n" +
            "```\n" +
            "\n" +
            "请你根据上述信息，按照以下步骤来分析学生的知识掌握情况：\n" +
            "1. 先根据标准答案判断学生答题的正确与否，如果错误则分析学生出现错误可能的原因；\n" +
            "2. 根据学生在某个题目类型下的正确率，判断学生在这个知识点掌握的程度；\n" +
            "3. 根据学生对知识点的掌握程度，给出学生的学习建议，建议的内容包含以下几个方面为：\n" +
            "    3.1. 对某个题目类型的掌握程度如何；\n" +
            "    3.2. 如果要学习推荐什么书籍，网站，文章；\n" +
            "    3.3. 对所有的问题进行总结，并说明在众多问题中哪个问题是当下最需要解决的问题；\n" +
            "    3.4. 如果问题只有一个，则不需要进行总结，即省略3.3内容；\n" +
            "4. 建议的内容格式如下（除了最后的总结，其它的掌握情况分析学生有多少类型的问题就写几点）：\n" +
            "\n" +
            "```\n" +
            "1. SpringBoot知识点掌握情况：\n" +
            "你对SpringBoot的使用比较熟练，但是对其中的原理还欠缺研究。\n" +
            "为了将来在Java行业的发展，你可以到SpringBoot官网（https://spring.io/projects/spring-boot)中进行学习，并结合Debug进行验证。\n" +
            "2. 【其它的知识点】：\n" +
            "...【这里省略对这个问题的分析】。\n" +
            "3. 总结：\n" +
            "你对Spring的框架了解还算及格，但是Java底层原理方面还有待提升，推荐对Java的底层进行重点学习。\n" +
            "```\n" +
            "\n" +
            "5. 返回的结果中只需要包含建议，不需要包含对学生答题结果的分析；";

    @Override
    public Long answerQuestion(AnswerResultAddRequest answerResultAddRequest, HttpServletRequest request) {
        Map<Long, String> selections = answerResultAddRequest.getOptions();
        // 定义列表用于记录每个题目是否正确
        List<Integer> selectResult = new ArrayList<>();
        List<Integer> judgeResult = new ArrayList<>();
        Set<Long> questionIds = selections.keySet();
        for (Long questionId : questionIds) {
            // 定义变量，记录该题的答题结果。
            int flag = 0;
            if (questionId == 23 && (selections.get(questionId) != null || StringUtils.isNotBlank(selections.get(questionId)))) {
                selectResult.add(1);
                continue;
            }
            Question question = questionService.getById(questionId);
            if (question.getType() == 0) {
                // 如果为选择题，则执行选择题的判题逻辑
                String answer = question.getAnswer();
                if (answer.equals(selections.get(questionId))) {
                    // 如果正确，则记录该题正确
                    flag = 1;
                }
                selectResult.add(flag);
            } else if (question.getType() == 1) {
                // 如果为判断题，则执行判断题的判题逻辑
                Integer isCorrect = question.getIsCorrect();
                if (isCorrect.toString().equals(selections.get(questionId))) {
                    flag = 1;
                }
                judgeResult.add(flag);
            }
        }
        // 合并两个数组
        List<Integer> result = new ArrayList<>();
        result.addAll(selectResult);
        result.addAll(judgeResult);

        long count = result.stream().filter(data -> data == 1).count();
        int score = (int) (BigDecimal.valueOf((double) count / result.size()).setScale(2, RoundingMode.HALF_UP).doubleValue() * 100);

        User loginUser = userService.getLoginUser(request);
        Long userId = loginUser.getId();

        // 如果已经存在某个题库的答题结果，则进行更新操作
        AnswerResultVO answerResultByBankId = this.getAnswerResultByBankId(answerResultAddRequest.getQuestionBankId(), request);
        if (answerResultByBankId != null) {
            this.update(new UpdateWrapper<AnswerResult>().lambda().eq(AnswerResult::getId, answerResultByBankId.getId())
                    .set(AnswerResult::getOptions, JSONUtil.toJsonStr(selections))
                    .set(AnswerResult::getJudgeOptions, JSONUtil.toJsonStr(result))
                    .set(AnswerResult::getUpdateTime, LocalDateTime.now())
                    .set(AnswerResult::getScore, score)
                    .set(AnswerResult::getAnalyzeResult, null));
            return answerResultByBankId.getId();
        }
        // 构造插入数据库的数据
        AnswerResult answerResult = new AnswerResult();
        BeanUtil.copyProperties(answerResultAddRequest, answerResult);

        answerResult.setJudgeOptions(JSONUtil.toJsonStr(result));
        answerResult.setOptions(JSONUtil.toJsonStr(selections));
        answerResult.setUserId(userId);
        answerResult.setQuestionBankName(answerResultAddRequest.getQuestionBankName());
        answerResult.setScore(score);
        answerResult.setAnalyzeResult(null);

        boolean save = this.save(answerResult);
        if (!save) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "添加答题信息失败");
        }
        return answerResult.getId();
    }

    @Override
    public AnswerResultVO getAnswerResultByBankId(Long bankId, HttpServletRequest request) {
        QueryWrapper<AnswerResult> wrapper = new QueryWrapper<>();
        Long userId = userService.getLoginUser(request).getId();
        wrapper.eq("questionBankId", bankId);
        wrapper.eq("userId", userId);

        List<AnswerResult> list = this.list(wrapper);
        if (list != null && !list.isEmpty()) {
            return AnswerResultVO.objToVo(list.get(0));
        } else {
            return null;
        }
    }

    @Override
    public Page<AnswerResultVO> listMyAnswerResultVOByPage(AnswerResultGetRequest answerResultGetRequest, HttpServletRequest request) {
        long current = answerResultGetRequest.getCurrent();
        long size = answerResultGetRequest.getPageSize();
        // 限制爬虫
        ThrowUtils.throwIf(size > 50, ErrorCode.PARAMS_ERROR);
        QueryWrapper<AnswerResult> wrapper = new QueryWrapper<>();
        if (answerResultGetRequest.getQuestionBankId() != null) {
            wrapper.eq("questionBankId", answerResultGetRequest.getQuestionBankId());
        }
        User loginUser = userService.getLoginUser(request);
        Long userId = loginUser.getId();
        wrapper.eq("userId", userId);
        Page<AnswerResult> answerResultPage = page(new Page<>(current, size), wrapper);
        Page<AnswerResultVO> answerResultVOPage = new Page<>(answerResultPage.getCurrent(), answerResultPage.getSize(), answerResultPage.getTotal());
        List<AnswerResult> records = answerResultPage.getRecords();
        List<AnswerResultVO> results = new ArrayList<>();
        for (AnswerResult record : records) {
            AnswerResultVO answerResultVO = AnswerResultVO.objToVo(record);
            results.add(answerResultVO);
        }
        answerResultVOPage.setRecords(results);
        return answerResultVOPage;
    }

    @Override
    public Page<AnswerResultVO> listAnswerResultVOByPage(AnswerResultGetRequest answerResultGetRequest, HttpServletRequest request) {
        long current = answerResultGetRequest.getCurrent();
        long size = answerResultGetRequest.getPageSize();
        // 限制爬虫
        ThrowUtils.throwIf(size > 50, ErrorCode.PARAMS_ERROR);
        QueryWrapper<AnswerResult> wrapper = new QueryWrapper<>();
        if (answerResultGetRequest.getQuestionBankId() != null) {
            wrapper.eq("questionBankId", answerResultGetRequest.getQuestionBankId());
        }
        Page<AnswerResult> answerResultPage = page(new Page<>(current, size), wrapper);
        Page<AnswerResultVO> answerResultVOPage = new Page<>(answerResultPage.getCurrent(), answerResultPage.getSize(), answerResultPage.getTotal());
        List<AnswerResult> records = answerResultPage.getRecords();
        List<AnswerResultVO> results = new ArrayList<>();
        for (AnswerResult record : records) {
            AnswerResultVO answerResultVO = AnswerResultVO.objToVo(record);
            results.add(answerResultVO);
        }
        answerResultVOPage.setRecords(results);
        return answerResultVOPage;
    }

    @Override
    public List<AnswerResult> getAnswerResultByUserId(Long id) {
        return this.list(new QueryWrapper<AnswerResult>().lambda().eq(AnswerResult::getUserId, id));
    }

    @Override
    public SseEmitter getAnalyzeResult(Long answerResultId) {
        SseEmitter sseEmitter = new SseEmitter(0L);
        AnswerResult answerResult = this.getOne(new QueryWrapper<AnswerResult>().lambda().eq(AnswerResult::getId, answerResultId));
        if(answerResult.getAnalyzeResult() != null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR , "参数错误");
        }
        // 构建Map对象
        Map<String , Object> tempMap = JSONUtil.parseObj(answerResult.getOptions());
        Map<Long , String> options = new HashMap<>();
        Set<String> keys = tempMap.keySet();
        for (String key : keys) {
            options.put(Long.parseLong(key) , tempMap.get(key).toString());
        }
        StringBuilder stringBuilder = new StringBuilder();
        // 调用AI请求分析结果
        Flowable<ModelData> modelDataFlowable = aiManager.doStreamRequest(AI_RESULT_ANALYZE_SYSTEM_MESSAGE, getUserMessage(answerResult.getQuestionBankName(),options), 0.99f);
        modelDataFlowable
                .observeOn(Schedulers.io())
                // 获取结果并转换为String类型
                .map(chunk->chunk.getChoices().get(0).getDelta().getContent())
                .map(message->message.replace("\n" , "\\x0A"))
                .doOnNext(c->{
                    sseEmitter.send(c);
                    System.out.println("当前发送的字符为："+c);
                    stringBuilder.append(c);
                })
                .doOnComplete(()->{
                    sseEmitter.complete();
                    String analyzeResult = stringBuilder.toString().replace("\\x0A" , "\n");
                    answerResult.setAnalyzeResult(analyzeResult);
                    this.update(new UpdateWrapper<AnswerResult>().lambda().eq(AnswerResult::getId , answerResultId).set(AnswerResult::getAnalyzeResult , analyzeResult));
                }).subscribe();
        return sseEmitter;
    }

    private String getUserMessage(String questionBankName, Map<Long, String> options) {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(questionBankName).append("\n");
        stringBuilder.append("[");
        Set<Long> questionIds = options.keySet();
        questionIds.forEach(questionId -> {
            Question question = questionService.getById(questionId);
            List<QuestionOption> questionOptions = JSONUtil.toList(question.getOptions(), QuestionOption.class);
            ResultAnalyzeRequest request = new ResultAnalyzeRequest();
            request.setTitle(question.getContent());
            request.setOptions(questionOptions);
            request.setQuestionAnswer(question.getAnswer());
            if(options.get(questionId)!=null && options.get(questionId).equals("1")){
                request.setUserAnswer("正确");
            }else if(options.get(questionId)!=null && options.get(questionId).equals("0")){
                request.setUserAnswer("错误");
            }else{
                request.setUserAnswer(options.get(questionId));
            }
            stringBuilder.append(JSONUtil.toJsonStr(request));
            stringBuilder.append(",");
        });
        stringBuilder.append("]");
        System.out.println("得到的userMessage为：");
        System.out.println(stringBuilder.toString());
        return stringBuilder.toString();
    }
}




